#pragma once


#include "singleton.h"

class XLock : public singleton
{
public:
    XLock(){}
    virtual ~XLock(){};
    virtual void    Lock() = 0;
    virtual void    UnLock() = 0;
    virtual BOOL    TryLock(int nTimeOut) = 0;
};


class XLockSection : public XLock
{
public:
    XLockSection()
    {
        InitializeCriticalSection(&m_Section);
    }

    virtual ~XLockSection()
    {
        DeleteCriticalSection(&m_Section);
    }

    virtual void    Lock()
    {
        EnterCriticalSection(&m_Section);
    }

    virtual void    UnLock()
    {
        LeaveCriticalSection(&m_Section);
    }

    virtual BOOL    TryLock(int nTimeOut)
    {
        return TryEnterCriticalSection(&m_Section);
    }

protected:
    CRITICAL_SECTION m_Section;
};

class XLockMutex : public XLock
{
public:
    XLockMutex()
    {
        m_hMutex = ::CreateMutex(NULL, FALSE, NULL);
    }

    virtual ~XLockMutex()
    {
        CloseHandle(m_hMutex);
        m_hMutex = NULL;
    }

    virtual void    Lock()
    {
        WaitForSingleObject(m_hMutex, INFINITE);
    }

    virtual void    UnLock()
    {
        ReleaseMutex(m_hMutex);
    }

    virtual BOOL    TryLock(int nTimeOut)
    {
        return (WaitForSingleObject(m_hMutex, nTimeOut) == WAIT_OBJECT_0);
    }

protected:
    HANDLE      m_hMutex;
};

class XLockEvent : public XLock
{
public:
    XLockEvent()
    {
        m_hEvent = ::CreateEvent(NULL, FALSE, TRUE, NULL);
    }

    virtual ~XLockEvent()
    {
        CloseHandle(m_hEvent);
        m_hEvent = NULL;
    }

    virtual void    Lock()
    {
        WaitForSingleObject(m_hEvent, INFINITE);
    }

    virtual void    UnLock()
    {
        SetEvent(m_hEvent);
    }

    virtual BOOL    TryLock(int nTimeOut)
    {
        return (WaitForSingleObject(m_hEvent, nTimeOut) == WAIT_OBJECT_0);
    }

protected:
    HANDLE      m_hEvent;
};

class XAutoLock : public singleton
{
public:
    XAutoLock(XLock* pLock)
    {
        m_pLock = pLock;
        if(m_pLock != NULL)
            m_pLock->Lock();
    }
    ~XAutoLock()
    {
        if(m_pLock != NULL)
        {
            m_pLock->UnLock();
            m_pLock = NULL;
        }
    }

protected:
    XLock*  m_pLock;
};
